package spring.superrun.record.mvc.Aop;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import spring.superrun.record.mvc.attribute.AllowedAnyone;
import spring.superrun.record.mvc.attribute.Authorize;
import spring.superrun.record.mvc.entity.SuperrunUserinfos;
import spring.superrun.record.mvc.service.SuperrunUserinfosService;
import spring.superrun.record.mvc.setup.CookieConfig;
import spring.superrun.record.mvc.setup.JWTConfig;
import spring.superrun.tool.newid.JwtUtils;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

import static spring.superrun.tool.newid.JwtUtils.verifyToken;

/**
 * 登录拦截器
 */
public class AuthenticationInterceptor implements HandlerInterceptor {
    @Resource
    private SuperrunUserinfosService _userInfosService;

    @Override
    /**
     * 可以做业务判断选择放行、拦截或者进行其他操作
     * @param request
     * @param response
     * @param handler
     * @return false 表示拦截, true 表示放行
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        try {
            //首先判断是否为jwtToken认证
            {
                // 从 http 请求头中取出 token
                String token = request.getHeader(JWTConfig.Authorization);
                String url = request.getRequestURI();
                // 如果不是映射到方法直接通过
                if(!(handler instanceof HandlerMethod)&&!url.equals("/")){
                    return true;
                }
                HandlerMethod handlerMethod=(HandlerMethod)handler;
                Method method=handlerMethod.getMethod();
                //检查是否有AllowedAnyone注释，有则跳过认证
                if (method.isAnnotationPresent(AllowedAnyone.class)) {
                    AllowedAnyone allowedAnyone = method.getAnnotation(AllowedAnyone.class);
                    if (allowedAnyone.required()) {
                        return true;
                    }
                }
                //检查有没有需要用户权限的注解
                if (method.isAnnotationPresent(Authorize.class)) {
                    Authorize authorize = method.getAnnotation(Authorize.class);
                    if (authorize.required()) {
                        // 执行认证
                        if (token == null) {
                            throw new RuntimeException("无token，请重新登录");
                        }
                        // 获取 token 中的 user id
                        String userId= JwtUtils.GetUserId(token);
                        SuperrunUserinfos user = _userInfosService.queryById(userId);
                        if (user == null) {
                            throw new RuntimeException("用户不存在，请重新登录");
                        }
                        // 验证 token
                        return verifyToken(token);
                    }
                }

            }

            //session和cookie认证
            //统一拦截（查询当前session是否存在user）(这里user会在每次登陆成功后，写入session)
            {
                Object thisUser=request.getSession().getAttribute(CookieConfig.SYSTEM_USER_SESSION);
                if(thisUser!=null){
                    // 已经登录
                    return true;
                }
                //cookie认证
                // 取出cookie中的信息，判断有没有登录
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        // 若登录，放行
                        if (cookie.getName().equals(CookieConfig.SYSTEM_USER_SESSION)&&cookie.getMaxAge()>0) {
                            return true;
                        }
                    }
                }
                request.getRequestDispatcher("/auth/login").forward(request,response);
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;//如果设置为false时，被请求时，拦截器执行到此处将不会继续操作
    }
}
